#include <unistd.h>
#include <fcntl.h>
#include "../Include/Timer.h"
#include "../Include/EventEngine.h"
#include "../Include/Assert.h"
#include "../Include/OS.h"

#ifdef LINUX_HAVE_TIMERFD
    #include <sys/timerfd.h>
#else
    #include "../Include/TimeManager.h"
#endif // LINUX_HAVE_TIMERFD

CTimer::CTimer(CEventEngine *lpEngine, ITimerEvent *lpTimerEvent) : CEvent(lpEngine)
{
	Assert(lpTimerEvent != NULL);

	m_lpTimerEvent = lpTimerEvent;

#ifdef LINUX_HAVE_TIMERFD
    m_nTimerFD = -1;
#else
    m_timerEventStruct.bDelFlag = True;
    m_timerEventStruct.nMin_heap_idx = -1;
#endif // LINUX_HAVE_TIMERFD
}

CTimer::~CTimer()
{
	KillTimer();
}

Bool CTimer::SetTimer(Int32 nInterval)
{
#ifdef LINUX_HAVE_TIMERFD
	m_nTimerFD = timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
	if (-1 == m_nTimerFD)
	{
		return False;
	}

	// itimerspec::it_value 的两个成员值同时设置为 0 时表示解除定时器
	//   如果想启用定时器时立即触发，可以将这两个值分别设置为 0 1
	itimerspec ts;
	ts.it_interval.tv_sec = nInterval / 1000;
	ts.it_interval.tv_nsec = (nInterval % 1000) * 1000000LL;
	ts.it_value.tv_sec = nInterval / 1000;
	ts.it_value.tv_nsec = (nInterval % 1000) * 1000000LL;
	
	if (timerfd_settime(m_nTimerFD, 0, &ts, NULL) != 0)
	{
		close(m_nTimerFD);
		m_nTimerFD = -1;
		return False;
	}

	if (!RegisterRead())
	{
		close(m_nTimerFD);
		m_nTimerFD = -1;
		return False;
	}

#else

    m_timerEventStruct.pTimer = this;
    m_timerEventStruct.nInterval = nInterval;
    CTimeManager *pTimeManager = m_lpEngine->GetTimeManager();
    pTimeManager->AddTimer(this);

    if (pTimeManager->IsTop(this))
    {
        m_lpEngine->PostMessage(1, NULL, NULL, pTimeManager);
    }
#endif // LINUX_HAVE_TIMERFD

	return True;
}

void CTimer::KillTimer()
{
#ifdef LINUX_HAVE_TIMERFD
	if (m_nTimerFD != -1)
	{
		Unregister();
		close(m_nTimerFD);
		m_nTimerFD = -1;
	}
#else
    m_lpEngine->GetTimeManager()->DelTimer(this);
#endif // LINUX_HAVE_EVENTFD
}

#ifndef LINUX_HAVE_TIMERFD

ITimerEvent * CTimer::GetTimerEvent()
{
    return m_lpTimerEvent;
}

TimerEventStruct* CTimer::GetTimerEventStruct()
{
    return &m_timerEventStruct;
}

#endif // LINUX_HAVE_EVENTFD

Int32 CTimer::GetFD() const
{
	return m_nTimerFD;
}

void CTimer::OnRead()
{
	Int64 lExpireTimes;
	read(m_nTimerFD, &lExpireTimes, sizeof(lExpireTimes));

	m_lpTimerEvent->OnTimer(this);
}

void CTimer::OnWrite()
{
	Assert(False);
}

void CTimer::OnError(Int32 nErrCode)
{
}

#ifdef LINUX_HAVE_TIMERFD

CTimerEx::CTimerEx(CEventEngine *lpEngine, weak_ptr<ITimerEventEx> wpTimerEventEx) : CEvent(lpEngine)
{
    m_nTimerFD = -1;
    m_wpTimerEvent = wpTimerEventEx;
}

CTimerEx::~CTimerEx()
{
    KillTimer();
}

Bool CTimerEx::SetTimer(Int32 nInterval)
{
    m_nTimerFD = timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
    if (-1 == m_nTimerFD)
    {
        return False;
    }

    // itimerspec::it_value 的两个成员值同时设置为 0 时表示解除定时器
    //   如果想启用定时器时立即触发，可以将这两个值分别设置为 0 1
    itimerspec ts;
    ts.it_interval.tv_sec = nInterval / 1000;
    ts.it_interval.tv_nsec = (nInterval % 1000) * 1000000LL;
    ts.it_value.tv_sec = nInterval / 1000;
    ts.it_value.tv_nsec = (nInterval % 1000) * 1000000LL;

    if (timerfd_settime(m_nTimerFD, 0, &ts, NULL) != 0)
    {
        close(m_nTimerFD);
        m_nTimerFD = -1;
        return False;
    }

    if (!RegisterRead())
    {
        close(m_nTimerFD);
        m_nTimerFD = -1;
        return False;
    }

    return True;
}

void CTimerEx::KillTimer()
{
    if (m_nTimerFD != -1)
    {
        Unregister();
        close(m_nTimerFD);
        m_nTimerFD = -1;
    }
}

Int32 CTimerEx::GetFD() const
{
    return m_nTimerFD;
}

void CTimerEx::OnRead()
{
    Int64 lExpireTimes;
    read(m_nTimerFD, &lExpireTimes, sizeof(lExpireTimes));

    shared_ptr<ITimerEventEx> spTimerEvent = m_wpTimerEvent.lock();
    if (spTimerEvent != NULL)
    {
        spTimerEvent->OnTimer(this);
    }
}

void CTimerEx::OnWrite()
{
    Assert(False);
}

void CTimerEx::OnError(Int32 nErrCode)
{
}

#endif // LINUX_HAVE_TIMERFD
